<script setup lang="ts" name="EditImageCropper">
import type Cropper from 'cropperjs'
type CropendResult = {
  imgBase64: string;
  imgInfo: Cropper.Data;
}
const props = defineProps({
  circled: { type: Boolean, default: true }
})

const emit = defineEmits(['fileChange'])

const initInfo: any = ref({
  info: null,
  isInit: true,
  currentOperate: '',
  filename: '',
  imageBase64: '',
  scaleX: 1,
  scaleY: 1,
  baseConfig: {
    isCropper: false,
    isKeepAspectRatio: false,
    width: 1,
    height: 1,
    aspectRatio: NaN
  },
  form: {
    src: '',
    title: '',
    alt: '',
    description: '',
    imagewidth: 0,
    imageheight: 0
  },
  options: {
    viewMode: 1,
    dragMode: 'move', // 拖拽图片的模式 crop: 形成新的裁剪框|move:图片可移动|none: 什么也没有
    initialAspectRatio: NaN, // 定义裁剪框的初始宽高比。默认和图片容器的宽高比相同。 只有在 aspectRatio 的值为 NaN时才可以设置。
    aspectRatio: NaN, // 定义裁剪框的固定宽高比。默认是自由比例
    minContainerWidth: 200, // 设置裁剪容器的最小宽度
    minContainerHeight: 100, // 设置裁剪容器的最小高度
    minCanvasWidth: 0, // 设置图片容器的最小宽度
    minCanvasHeight: 0, // 设置图片容器的最小高度
    minCropBoxWidth: 0, // 设置裁剪框的最小宽度 相对于页面，而非图片
    minCropBoxHeight: 0 // 设置裁剪框的最小高度 相对于页面，而非图片
  }
})

const getInitInfo = (v) => {
  initInfo.value.info = v
  initInfo.value.baseConfig.width = v.imagewidth
  initInfo.value.baseConfig.height = v.imageheight
  initInfo.value.form.src = v.base64
  initInfo.value.form.title = v.title ? v.title : ''
  initInfo.value.form.alt = v.alt ? v.alt : ''
  initInfo.value.form.description = v.description ? v.description : ''
  initInfo.value.form.imagewidth = v.imagewidth
  initInfo.value.form.imageheight = v.imageheight
}

const resetInitInfo = () => {
  initInfo.value.info = null
  initInfo.value.isInit = true
  initInfo.value.currentOperate = ''
  initInfo.value.filename = ''
  initInfo.value.imageBase64 = ''
  initInfo.value.scaleX = 1
  initInfo.value.scaleY = 1
  initInfo.value.baseConfig.isCropper = false
  initInfo.value.baseConfig.isKeepAspectRatio = false
  initInfo.value.baseConfig.width = 1
  initInfo.value.baseConfig.height = 1
  initInfo.value.baseConfig.aspectRatio = NaN
  initInfo.value.form.src = ''
  initInfo.value.form.title = ''
  initInfo.value.form.alt = ''
  initInfo.value.form.description = ''
  initInfo.value.form.imagewidth = 0
  initInfo.value.form.imageheight = 0
}

const getChangeValue = () => {
  return {
    filename: initInfo.value.filename,
    value: initInfo.value.imageBase64,
    isInit: initInfo.value.isInit,
    form: initInfo.value.form
  }
}

// 子组件将方法暴露给父组件
defineExpose({ getInitInfo, resetInitInfo, getChangeValue })

const cropper = ref<Cropper>()

// 宽度设置改变触发事件
const widthChangeHandler = (v) => {
  console.log(v)
  if (cropper.value) {
    const imgInfo = cropper.value.getData()
    if (!initInfo.value.baseConfig.isCropper) {
      initInfo.value.baseConfig.isCropper = true
      cropper.value.crop()
    }
    imgInfo.width = v
    if (initInfo.value.baseConfig.isKeepAspectRatio) {
      imgInfo.height = v / initInfo.value.baseConfig.aspectRatio
    } else {
      imgInfo.height = initInfo.value.form.imageheight
    }
    cropper.value.setData(imgInfo)
  }
}

// 高度设置改变触发事件
const heightChangeHandler = (v) => {
  console.log(v)
  if (cropper.value) {
    const imgInfo = cropper.value.getData()
    if (!initInfo.value.baseConfig.isCropper) {
      initInfo.value.baseConfig.isCropper = true
      cropper.value.crop()
    }
    imgInfo.height = v
    if (initInfo.value.baseConfig.isKeepAspectRatio) {
      imgInfo.width = v * initInfo.value.baseConfig.aspectRatio
    } else {
      imgInfo.width = initInfo.value.form.imagewidth
    }
    cropper.value.setData(imgInfo)
  }
}

// 保持宽高比切换事件
const changeAspectRatioHandler = (v) => {
  if (cropper.value) {
    const cropBoxInfo = cropper.value.getCropBoxData()
    if (v) {
      const imgInfo = cropper.value.getData()
      console.log(cropBoxInfo, '裁剪框数据信息')
      console.log(imgInfo, '裁剪数据信息232323')
      if (Math.round(imgInfo.width) === 0) {
        console.log('初始化')
        cropper.value.setAspectRatio(initInfo.value.info.imagewidth / initInfo.value.info.imageheight)
        initInfo.value.baseConfig.aspectRatio = initInfo.value.info.imagewidth / initInfo.value.info.imageheight
      } else {
        console.log('裁剪后')
        initInfo.value.baseConfig.aspectRatio = Math.round(imgInfo.width) / Math.round(imgInfo.height)
        cropper.value.setAspectRatio(Math.round(imgInfo.width) / Math.round(imgInfo.height))
        cropper.value.setCropBoxData(cropBoxInfo)
      }
    } else {
      initInfo.value.baseConfig.aspectRatio = NaN
      cropper.value.setAspectRatio(NaN)
      cropper.value.setCropBoxData(cropBoxInfo)
    }
  }
}

// 裁剪框发生变化触发事件
const handleCropend = ({ imgBase64, imgInfo }: CropendResult) => {
  initInfo.value.imageBase64 = imgBase64
  initInfo.value.isInit = false
  console.log(imgInfo, '图片裁剪信息')
  if (initInfo.value.baseConfig.isCropper) {
    initInfo.value.form.imagewidth = Math.round(imgInfo.width)
    initInfo.value.form.imageheight = Math.round(imgInfo.height)
  } else {
    if (imgInfo.width === 0) {
      if (initInfo.value.currentOperate === 'reset') {
        initInfo.value.isInit = true
        initInfo.value.form.imagewidth = initInfo.value.info.imagewidth
        initInfo.value.form.imageheight = initInfo.value.info.imageheight
      } else {
        initInfo.value.form.imagewidth = initInfo.value.baseConfig.width
        initInfo.value.form.imageheight = initInfo.value.baseConfig.height
      }
    } else {
      initInfo.value.baseConfig.isCropper = true
      initInfo.value.form.imagewidth = Math.round(imgInfo.width)
      initInfo.value.form.imageheight = Math.round(imgInfo.height)
      if (cropper.value) {
        cropper.value.crop()
      }
    }
  }
  emit('fileChange', {
    filename: initInfo.value.filename,
    value: initInfo.value.imageBase64,
    isInit: initInfo.value.isInit,
    form: initInfo.value.form
  })
}

// 裁剪框确认事件
const saveCropper = () => {
  initInfo.value.baseConfig.width = initInfo.value.form.imagewidth
  initInfo.value.baseConfig.height = initInfo.value.form.imageheight
  initInfo.value.baseConfig.isCropper = false
  initInfo.value.currentOperate = ''
  initInfo.value.form.src = initInfo.value.imageBase64
  if (cropper.value) {
    cropper.value.replace(initInfo.value.imageBase64)
    cropper.value.clear()
  }
}

// 裁剪实例完成触发事件
const handleReady = (cropperInstance: Cropper) => {
  cropper.value = cropperInstance
  emit('fileChange', {
    filename: initInfo.value.filename,
    value: initInfo.value.imageBase64,
    isInit: initInfo.value.isInit,
    form: initInfo.value.form
  })
}

// 工具条点击事件
const handlerToolbar = (type: string, event: string, arg?: number) => {
  if (initInfo.value.form.src) {
    initInfo.value.currentOperate = type
    if (event === 'scaleX') {
      initInfo.value.scaleX = arg = initInfo.value.scaleX === -1 ? 1 : -1
    }
    if (event === 'scaleY') {
      initInfo.value.scaleY = arg = initInfo.value.scaleY === -1 ? 1 : -1
    }
    if (event !== 'cropper') {
      cropper?.value?.[event]?.(arg)
      initInfo.value.isInit = false
      if (event === 'reset') {
        console.log(cropper.value, '裁剪实例111')
        initInfo.value.isInit = true
        initInfo.value.baseConfig.isCropper = false
        initInfo.value.form.imagewidth = initInfo.value.info.imagewidth
        initInfo.value.form.imageheight = initInfo.value.info.imageheight
        if (cropper.value) {
          cropper.value.replace(initInfo.value.info.url)
          initInfo.value.form.src = initInfo.value.info.url
          if (initInfo.value.baseConfig.isKeepAspectRatio) {
            cropper.value.setAspectRatio(initInfo.value.info.imagewidth / initInfo.value.info.imageheight)
          } else {
            cropper.value.setAspectRatio(NaN)
          }
          cropper.value.clear()
        }
      }
    } else {
      initInfo.value.isInit = false
      initInfo.value.baseConfig.isCropper = true
      if (cropper.value) {
        cropper.value.crop()
      }
    }
  }
}
</script>

<template>
  <div class="cropper-wrap">
    <div class="cropper-left">
      <div class="cropper-content">
        <div :class="['cropper-image-wrap', initInfo.baseConfig.isCropper ? 'cropper' : '']">
          <CropperImage v-if="initInfo.form.src !== ''" :src="initInfo.form.src" :alt="initInfo.form.alt" :mimeType="initInfo.info.mimetype" height="330px" :circled="props.circled" :options="initInfo.options" @cropend="handleCropend" @ready="handleReady" />
          <div v-if="initInfo.baseConfig.isCropper" class="image-size-text">
            图片尺寸：{{ initInfo.form.imagewidth }}x{{
          initInfo.form.imageheight }}
          </div>
          <div v-if="initInfo.baseConfig.isCropper" class="btn-save" @click="saveCropper">确认</div>
        </div>
        <div class="cropper-toolbar">
          <div class="cropper-operate">
            <div :class="['item-operate', initInfo.form.src !== '' ? '' : 'disabled', initInfo.currentOperate === 'reset' ? 'active' : '']" @click="handlerToolbar('reset', 'reset')">
              <div class="item-icon"><svg-icon icon="ad:reload-outlined" /></div>
              <div class="item-text">重置</div>
            </div>
            <div :class="['item-operate', initInfo.form.src !== '' ? '' : 'disabled', initInfo.currentOperate === 'rotateLeft' ? 'active' : '']" @click="handlerToolbar('rotateLeft', 'rotate', -45)">
              <div class="item-icon"><svg-icon icon="ad:rotate-left-outlined" /></div>
              <div class="item-text">向左旋转</div>
            </div>
            <div :class="['item-operate', initInfo.form.src !== '' ? '' : 'disabled', initInfo.currentOperate === 'rotateRight' ? 'active' : '']" @click="handlerToolbar('rotateRight', 'rotate', 45)">
              <div class="item-icon"><svg-icon icon="ad:rotate-right-outlined" /></div>
              <div class="item-text">向右旋转</div>
            </div>
            <div :class="['item-operate', initInfo.form.src !== '' ? '' : 'disabled', initInfo.currentOperate === 'horizontalFlip' ? 'active' : '']" @click="handlerToolbar('horizontalFlip', 'scaleX')">
              <div class="item-icon"><svg-icon icon="ci:horizontal-flip" /></div>
              <div class="item-text">水平翻转</div>
            </div>
            <div :class="['item-operate', initInfo.form.src !== '' ? '' : 'disabled', initInfo.currentOperate === 'verticalFlip' ? 'active' : '']" @click="handlerToolbar('verticalFlip', 'scaleY')">
              <div class="item-icon"><svg-icon icon="ci:vertical-flip" /></div>
              <div class="item-text">垂直翻转</div>
            </div>
            <div :class="['item-operate', initInfo.form.src !== '' ? '' : 'disabled', initInfo.currentOperate === 'zoomIn' ? 'active' : '']" @click="handlerToolbar('zoomIn', 'zoom', 0.1)">
              <div class="item-icon"><svg-icon icon="ad:zoom-in-outlined" /></div>
              <div class="item-text">放大</div>
            </div>
            <div :class="['item-operate', initInfo.form.src !== '' ? '' : 'disabled', initInfo.currentOperate === 'zoomOut' ? 'active' : '']" @click="handlerToolbar('zoomOut', 'zoom', -0.1)">
              <div class="item-icon"><svg-icon icon="ad:zoom-out-outlined" /></div>
              <div class="item-text">缩小</div>
            </div>
            <div :class="['item-operate', initInfo.form.src !== '' ? '' : 'disabled', initInfo.currentOperate === 'cropper' ? 'active' : '', initInfo.baseConfig.isCropper ? 'cropper' : '']" @click="handlerToolbar('cropper', 'cropper')">
              <div class="item-icon"><svg-icon icon="ri:crop-line" /></div>
              <div class="item-text">裁剪</div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="cropper-right">
      <ElForm label-width="auto" label-position="top">
        <ElFormItem label="图片名称：">
          <ElInput v-model="initInfo.form.title" clearable maxlength="50" show-word-limit placeholder="" />
        </ElFormItem>
        <ElFormItem label="图片alt：">
          <ElInput v-model="initInfo.form.alt" type="textarea" clearable maxlength="150" :autosize="false" resize="none" show-word-limit placeholder="" />
        </ElFormItem>
        <ElFormItem label="图片描述：">
          <ElInput v-model="initInfo.form.description" type="textarea" clearable maxlength="150" :autosize="false" resize="none" show-word-limit placeholder="" />
        </ElFormItem>
        <div class="el-form-group">
          <ElFormItem label="宽度：">
            <ElInputNumber v-model="initInfo.form.imagewidth" :min="0" :max="initInfo.info && initInfo.info.imagewidth" @change="widthChangeHandler" />
          </ElFormItem>
          <ElFormItem class="label-text">
            <p>px</p>
          </ElFormItem>
          <ElFormItem label="高度：">
            <ElInputNumber v-model="initInfo.form.imageheight" type="number" :min="0" :max="initInfo.info && initInfo.info.imageheight" @change="heightChangeHandler" />
          </ElFormItem>
          <ElFormItem class="label-text">
            <p>px</p>
          </ElFormItem>
          <ElFormItem class="label-text">
            <ElCheckbox v-model="initInfo.baseConfig.isKeepAspectRatio" @change="changeAspectRatioHandler">保持宽高比</ElCheckbox>
          </ElFormItem>
        </div>
      </ElForm>
    </div>
  </div>
</template>

<style scoped lang="scss">
.cropper-wrap {
  display: flex;
  flex-direction: row;

  .cropper-left,
  .cropper-right {
    height: 400px;
  }

  .cropper-left {
    width: 50%;
  }

  .cropper-right {
    width: 50%;
    padding-left: var(--el-space);

    .el-form {
      overflow: hidden;

      .el-form-item {
        :deep(.el-form-item__content) {
          .el-textarea {
            .el-textarea__inner {
              height: 88px;
            }
          }
        }
      }
    }
  }

  .cropper-content {
    position: relative;

    .cropper-image-wrap {
      position: relative;
      height: 330px;
      background: #eee;

      &.cropper {
        background-image: linear-gradient(45deg,
            rgba(0, 0, 0, 0.25) 25%,
            transparent 0,
            transparent 75%,
            rgba(0, 0, 0, 0.25) 0),
          linear-gradient(45deg,
            rgba(0, 0, 0, 0.25) 25%,
            transparent 0,
            transparent 75%,
            rgba(0, 0, 0, 0.25) 0);
        background-position: 0 0, 12px 12px;
        background-size: 24px 24px;
      }

      .image-size-text {
        position: absolute;
        top: 10px;
        left: 10px;
        z-index: 10;
        height: 20px;
        padding: 0 5px;
        font-size: 12px;
        line-height: 20px;
        color: #fff;
        background: rgba(0, 0, 0, 0.5);
        border-radius: 2px;
      }

      .btn-save {
        position: absolute;
        bottom: 10px;
        left: 50%;
        width: 98px;
        height: 26px;
        margin-left: -49px;
        font-size: 12px;
        line-height: 24px;
        color: var(--el-color-primary);
        text-align: center;
        cursor: pointer;
        background-color: #fff;
        border: 1px solid var(--el-color-primary);
        border-radius: 2px;
      }
    }
  }

  .cropper-toolbar {
    display: flex;
    flex: 1;
    align-items: center;
    justify-content: space-between;
    margin-top: 5px;

    .cropper-operate {
      display: flex;
      flex: 1;

      .item-operate {
        flex: 1;
        cursor: pointer;

        &:hover {
          .item-icon {
            background-color: var(--el-color-primary-light-9);
          }
        }

        &.disabled {
          cursor: not-allowed;
        }

        &.active {
          .item-icon {
            color: var(--el-color-primary);
            background-color: var(--el-color-primary-light-9);
          }

          .item-text {
            color: var(--el-color-primary);
          }
        }

        &.cropper {
          .item-icon {
            color: var(--el-color-primary);
          }
        }

        .item-icon {
          display: flex;
          align-items: center;
          justify-content: center;
          height: 32px;
          background-color: var(--el-fill-color-light);

          .el-icon {
            font-size: 20px !important;
          }
        }

        .item-text {
          display: flex;
          align-items: center;
          justify-content: center;
          height: 16px;
          margin-top: 2px;
          font-size: 12px;
        }
      }

      .item-operate+.item-operate {
        margin-left: 5px;
      }
    }
  }

  .cropper-preview {
    width: 224px;
    height: 224px;
    margin: 0 auto;
    overflow: hidden;
    border: 1px solid var(--el-border-color-lighter);

    img {
      width: 100%;
      height: 100%;
    }
  }

  .cropper-group {
    display: flex;
    padding-top: 20px;
    margin-top: 20px;
    border-top: 1px solid var(--el-border-color-lighter);
    align-items: center;
    justify-content: space-around;
  }
}

.el-form-group {
  display: flex;

  .el-form-item+.el-form-item {
    margin-top: 0;
  }

  .label-text {
    :deep(.el-form-item__content) {
      margin-top: 28px;

      p {
        margin-right: 10px;
        line-height: 44px;
      }
    }
  }
}
</style>
